 # -*- coding: utf-8 -*-

import db
reload( db)
from db import McfConnector

import Attribute
reload( Attribute)
from Attribute import *


class AE():
	"""Anatomical Entity"""
	def __init__(self, libmyCF, AE_id, name="", definition="",source="",curator=""):
		self.libmyCF= libmyCF
		self.AE_id = AE_id
		self.name = name
		self.definition = definition
		self.source = source
		self.curator = curator


	def getAttributes( self ):
		"""Return the attributes of this AE but also the inherited"""
		attributes = self.getOwnAttributes()
		
		relType = self.libmyCF.ontology.getRelationTypeNamed( "is_a")
		relID = relType.getId()
		
		stack = [ self]
		while len( stack) > 0:
			# Get the own attributes of this AE
			ae = stack.pop()
			aeAttributes = ae.getOwnAttributes()
			
			# Add the new attributes of this entity
			for att in aeAttributes:
				found = False
				for everFoundAttribute in attributes:
					if att.getName() == everFoundAttribute.getName():
						found = True
						break
				
				if not found:
					attributes.append( att)
			
			# Get the AE parent of the current AE
			for entity in ae.get_l_parent( relID):
				stack.append( entity)
		
		return attributes


	def getAttributesNamed( self, name):  
		#Should not use a sql request to interrogate the remote database but search the result in the local ontology
		#Should not use a sql request to interrogate the remote database but search the result in the local ontology
		"""Retrieve the attribute of this AE with the name 'name' from DataBase"""
		attributes = []
		query="SELECT * FROM Attributes AS A INNER JOIN (SELECT * FROM Attribute_Type WHERE name =\"%s\") AS AT ON ( A.attribute_type_id = AT.attribute_type_id) WHERE A.AE_id = \"%d\""%( name, self.AE_id)
		for data in self.libmyCF.connector.mcfQuery(query):
			attributes.append(Attribute(libmyCF=self.libmyCF, attribute_id=int(data[0]), attribute_type_id=int(data[1]), AE_id=int(data[2]), value=data[3]))
		
		# If no result, search for inheritance
		if len(attributes) == 0:
			allAttributes = self.getAttributes()
			for att in allAttributes:
				if att.getName() == name :
					attributes.append( att)
					break
		
		return attributes
	
		#def getAttributesNamedFromOnto( self, name):


	def get_l_child(self, relation_type_id):
		"""Return a list of children using the provided relation-type_id"""
		l_child=[]
		for r in self.libmyCF.ontology.all_relations:
			if r.relation_type_id == relation_type_id:
				if r.parent== self.AE_id:
					l_child.append( self.libmyCF.ontology.all_AEs[r.child])
		return l_child


	def get_l_parent(self, relation_type_id):
		"""Return a list of parents using the provided relation-type_id"""
		# the list normaly contains only one element
		l_parent=[]
		for r in self.libmyCF.ontology.all_relations:
			if r.relation_type_id == relation_type_id:
				if r.child== self.AE_id:
					l_parent.append( self.libmyCF.ontology.all_AEs[r.parent])
		return l_parent


	def get_l_relations(self):
		"""Return the list of all relations in which an AE is implicated"""
		# return Collection_of_Relations(self)
		l = []
		for relation in self.libmyCF.ontology.all_relations:
			if relation.child == self.AE_id or relation.parent == self.AE_id :
				l.append(relation)
		return l

	def get_is_a(self): #Should not use a sql request to interrogate the remote database but search the result in the local ontology
		"""Return the parent in the taxanomie 'is_a'"""
		query="SELECT Anatomical_Entities.name FROM Anatomical_Entities WHERE Anatomical_Entities.AE_id=(SELECT Relations.parent from Relations where Relations.relation_type_id=2 AND child="+ str(self.AE_id) + ");"
		parent = self.libmyCF.connector.mcfQuery(query)
		if parent <> []:
			return parent[0][0]
		else:
			return "Not yet defined"
		
#	def getId( self):
#		return self.AE_id
#
#
#	def getName( self):
#		"""Convenient function which returns the name of the Anatomical Entity"""
#		return self.name
#
#	def getSource( self):
#		"""Convenient function which returns the name of the Ontology source (FMA, MyCF...)"""
#		return self.source
#	
#	def getCurator( self):
#		"""Convenient function which returns the name of the Curator (should be curator's email)"""
#		return self.curator


	def getOwnAttributes( self):
		"""Retrieve the attribute of this AE from DataBase"""
		attributes = []
		for attribute in self.libmyCF.ontology.all_attributes :
			if attribute.AE_id == self.AE_id :
				attributes.append(attribute)
		return attributes


	def getOwnAttributes_db( self): #Should not use a sql request to interrogate the remote database but search the result in the local ontology
		"""Retrieve the attribute of this AE from DataBase"""
		attributes = []
		query="SELECT * FROM Attributes AS A INNER JOIN (SELECT * FROM Attribute_Type) AS AT ON ( A.attribute_type_id = AT.attribute_type_id) WHERE A.AE_id = \"%d\""%( self.AE_id)
		for data in self.libmyCF.connector.mcfQuery(query):
			attributes.append(Attribute(libmyCF=self.libmyCF, attribute_id=int(data[0]), attribute_type_id=int(data[1]), AE_id=int(data[2]), value=data[3]))
			
		return attributes


	def isA ( self, nameList):
		"""Retun true if this AE is a child of an AE listed in 'nameList' according to the relation type 'is_a'"""
		return self.isAChildOf( nameList, "is_a" )


	## Warning !! You must call this function only on relation type defining a tree !! ( and not a cyclic graph) or it will be endless ...
	def isAChildOf( self, nameList, relationTypeName):
		"""Return a name contained in 'nameList' if this AE is a direct or indirect child of it, according to the relation type 'relationTypeName'"""
		relType = self.libmyCF.ontology.getRelationTypeNamed( relationTypeName)
		relID = relType.relation_type_id
		
		parent_dic = {}
		for AE_id in self.libmyCF.ontology.all_AEs :
			parent_dic[int(AE_id)]=[]
			
		#get a dictionary of all AE_ids of child AE for an AE with its id as key of the dictionary
		for relation in  self.libmyCF.ontology.all_relations :			
			if relation.relation_type_id==relID:
				#child_dic[int(relation.parent)].append(relation.child)
				parent_dic[int(relation.child)].append(relation.parent)
		
		stack = parent_dic[self.AE_id]


		while len(stack)>0 :
			parent_AE_id = stack.pop()
			parent_AE_name =self.libmyCF.ontology.all_AEs[parent_AE_id].name 
			#print ('%s'%parent_AE_name)
			for AE_name in nameList :
				#print ('%s'%AE_name)
				if AE_name == parent_AE_name :
					return True
			for id_parent in parent_dic[parent_AE_id] :
				stack.append(id_parent)
			
		return False
#		done = False
#		stack = self.get_l_parent( relID)
#		while not done :
#			if( stack.__len__() == 0) : # If the stack is empty, we haven't found a good type
#				done = True
#			else:
#				# Get the name of the next parent AE
#				entity = stack.pop()
#				
#				# If this is an interesting type, get it
#				for relTName in nameList:
#					if entity.name == relTName :
#						done = True
#						return relTName
#				
#				# Append the other parents to the stack
#				for ae in entity.get_l_parent( relID) :
#					stack.append( ae)
#		return ""


	def partOfWhich( self, nameList):
		"""Returns true if this AE is a part of an AE listed in 'nameList' according to the relation type 'part_of'"""
		return self.isAChildOf( nameList, "part_of" )

	
	def update(self, name="", definition="", source="", curator=""):
		"""Update name,definition, source and curator of a given AE """
		if( name != ""): self.name = name.capitalize()
		#if( definition != ""): self.definition = definition
		#if( source != ""): self.source = source
		#if( curator != ""): self.curator = curator
		self.definition = definition
		self.source = source
		self.curator = curator
		
		#print self.name, self.source, self.curator
		#update mysql database
		#query="UPDATE Anatomical_Entities SET name='"+ self.name +"', definition='"+ self.definition +"' WHERE AE_id = "+ str(self.AE_id)
		query ="UPDATE Anatomical_Entities SET name='"+ self.name +"', definition='"+ self.libmyCF.ontology.addslashes(self.definition) +"', source='"+ self.libmyCF.ontology.addslashes(self.source) +"', curator='"+ self.libmyCF.ontology.addslashes(self.curator) +"' WHERE AE_id = "+ str(self.AE_id)
		sql= self.libmyCF.connector.mcfQueryExec(query)
		#update local ontology
		updated_AE = {self.AE_id : AE( libmyCF=self.libmyCF,AE_id=self.AE_id,name=self.name, definition=self.definition, source=self.source, curator=self.curator)}
		self.libmyCF.ontology.all_AEs.update(updated_AE)   
		return sql
